wclass.lpszClassName = "GdkDisplayChange";
wclass.lpfnWndProc = display_change_window_procedure;
wclass.hInstance = _gdk_app_hmodule;
+ wclass.style = CS_OWNDC;
klass = RegisterClass (&wclass);
if (klass)
if (display_win32->hwnd != NULL)
{
+ if (display_win32->dummy_context_wgl.hglrc != NULL)
+ {
+ wglMakeCurrent (NULL, NULL);
+ wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
+ display_win32->dummy_context_wgl.hglrc = NULL;
+ }
+
+ if (display_win32->dummy_context_wgl.hdc != NULL)
+ {
+ ReleaseDC (display_win32->hwnd, display_win32->dummy_context_wgl.hdc);
+ display_win32->dummy_context_wgl.hdc = NULL;
+ }
+
DestroyWindow (display_win32->hwnd);
display_win32->hwnd = NULL;
}
return _gdk_win32_get_setting (name, value);
}
+static gboolean
+gdk_win32_display_init_gl_backend (GdkDisplay *display,
+ GError **error)
+{
+#ifdef GDK_WIN32_ENABLE_EGL
+ if (GDK_DISPLAY_DEBUG_CHECK (display, GL_EGL))
+ return gdk_win32_display_init_egl (display, error);
+#endif
+ if (GDK_DISPLAY_DEBUG_CHECK (display, GL_WGL))
+ return gdk_win32_display_init_wgl (display, error);
+
+ /* No env vars set, do the regular GL initialization.
+ *
+ * We try EGL first if supported, but are very picky about what we accept.
+ * If that fails, we try to go with WGL instead.
+ * And if that also fails, we try EGL again, but this time accept anything.
+ *
+ * The idea here is that EGL is the preferred method going forward, but WGL is
+ * the tried and tested method that we know works. So if we detect issues with
+ * EGL, we want to avoid using it in favor of WGL.
+ */
+
+#ifdef GDK_WIN32_ENABLE_EGL
+ if (gdk_win32_display_init_egl (display, error))
+ return TRUE;
+#endif
+ g_clear_error (error);
+
+ if (gdk_win32_display_init_wgl (display, error))
+ return TRUE;
+ g_clear_error (error);
+
+#ifdef GDK_WIN32_ENABLE_EGL
+ return gdk_win32_display_init_egl (display, error);
+#else
+ return FALSE;
+#endif
+}
+
+static GdkGLContext *
+gdk_win32_display_init_gl (GdkDisplay *display,
+ GError **error)
+{
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ GdkGLContext *gl_context = NULL;
+
+ if (!gdk_win32_display_init_gl_backend (display, error))
+ return NULL;
+
+#ifdef GDK_WIN32_ENABLE_EGL
+ if (display_win32->egl_disp)
+ gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL, "display", display, NULL);
+ else
+#endif
+ if (display_win32->wgl_pixel_format != 0)
+ gl_context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_WGL, "display", display, NULL);
+
+ g_return_val_if_fail (gl_context != NULL, NULL);
+
+ return gl_context;
+}
+
/**
* gdk_win32_display_get_egl_display:
* @display: (type GdkWin32Display): a Win32 display
#ifdef GDK_WIN32_ENABLE_EGL
display_win32 = GDK_WIN32_DISPLAY (display);
- if (display_win32->have_wgl)
+ if (display_win32->wgl_pixel_format != 0)
return NULL;
return display_win32->egl_disp;
display_class->get_setting = gdk_win32_display_get_setting;
display_class->set_cursor_theme = gdk_win32_display_set_cursor_theme;
+ display_class->init_gl = gdk_win32_display_init_gl;
_gdk_win32_surfaceing_init ();
}
funcIsWow64Process2 isWow64Process2;
} GdkWin32KernelCPUFuncs;
+typedef struct
+{
+ HDC hdc;
+ HGLRC hglrc;
+} GdkWin32GLDummyContextWGL;
+
struct _GdkWin32Display
{
GdkDisplay display;
HWND hwnd;
/* WGL/OpenGL Items */
- guint have_wgl : 1;
+ GdkWin32GLDummyContextWGL dummy_context_wgl;
+ int wgl_pixel_format;
guint gl_version;
#ifdef GDK_WIN32_ENABLE_EGL
/* EGL (Angle) Items */
- guint have_egl : 1;
guint egl_version;
EGLDisplay egl_disp;
+ EGLConfig egl_config;
HDC hdc_egl_temp;
#endif
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-win32.c: Win32 specific OpenGL wrappers
+ *
+ * Copyright © 2014 Emmanuele Bassi
+ * Copyright © 2014 Alexander Larsson
+ * Copyright © 2014 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkprivate-win32.h"
+#include "gdksurface-win32.h"
+#include "gdkglcontext-win32.h"
+#include "gdkdisplay-win32.h"
+
+#include "gdkwin32display.h"
+#include "gdkwin32glcontext.h"
+#include "gdkwin32misc.h"
+#include "gdkwin32screen.h"
+#include "gdkwin32surface.h"
+
+#include "gdkglcontext.h"
+#include "gdksurface.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+
+#include <cairo.h>
+#include <epoxy/egl.h>
+
+struct _GdkWin32GLContextEGL
+{
+ GdkWin32GLContext parent_instance;
+
+ /* EGL (Angle) Context Items */
+ EGLContext egl_context;
+ guint do_frame_sync : 1;
+};
+
+typedef struct _GdkWin32GLContextClass GdkWin32GLContextEGLClass;
+
+G_DEFINE_TYPE (GdkWin32GLContextEGL, gdk_win32_gl_context_egl, GDK_TYPE_WIN32_GL_CONTEXT)
+
+static void
+gdk_win32_gl_context_egl_dispose (GObject *gobject)
+{
+ GdkGLContext *context = GDK_GL_CONTEXT (gobject);
+ GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (gobject);
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context));
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+
+ if (display_win32 != NULL)
+ {
+ if (eglGetCurrentContext () == context_egl->egl_context)
+ eglMakeCurrent(display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+
+ GDK_NOTE (OPENGL, g_message ("Destroying EGL (ANGLE) context"));
+
+ eglDestroyContext (display_win32->egl_disp,
+ context_egl->egl_context);
+ context_egl->egl_context = EGL_NO_CONTEXT;
+ }
+
+ G_OBJECT_CLASS (gdk_win32_gl_context_egl_parent_class)->dispose (gobject);
+}
+
+static gboolean
+is_egl_force_redraw (GdkSurface *surface)
+{
+ /* We only need to call gdk_window_invalidate_rect () if necessary */
+ if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context))
+ {
+ GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
+
+ return impl->egl_force_redraw_all;
+ }
+ return FALSE;
+}
+
+static void
+reset_egl_force_redraw (GdkSurface *surface)
+{
+ if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context))
+ {
+ GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
+
+ if (impl->egl_force_redraw_all)
+ impl->egl_force_redraw_all = FALSE;
+ }
+}
+
+static void
+gdk_win32_gl_context_egl_end_frame (GdkDrawContext *draw_context,
+ cairo_region_t *painted)
+{
+ GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
+ GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+ GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
+ cairo_rectangle_int_t whole_window;
+ EGLSurface egl_surface;
+
+ GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->end_frame (draw_context, painted);
+
+ gdk_gl_context_make_current (context);
+ whole_window =
+ (GdkRectangle) { 0, 0,
+ gdk_surface_get_width (surface),
+ gdk_surface_get_height (surface)
+ };
+
+ egl_surface = gdk_win32_surface_get_egl_surface (surface, display_win32->egl_config, FALSE);
+
+ if (is_egl_force_redraw (surface))
+ {
+ GdkRectangle rect = {0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface)};
+
+ /* We need to do gdk_window_invalidate_rect() so that we don't get glitches after maximizing or
+ * restoring or using aerosnap
+ */
+ gdk_surface_invalidate_rect (surface, &rect);
+ reset_egl_force_redraw (surface);
+ }
+
+ eglSwapBuffers (display_win32->egl_disp, egl_surface);
+}
+
+#ifndef EGL_PLATFORM_ANGLE_ANGLE
+#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
+#endif
+
+#ifndef EGL_PLATFORM_ANGLE_TYPE_ANGLE
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
+#endif
+
+#ifndef EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
+#endif
+
+static EGLDisplay
+gdk_win32_get_egl_display (GdkWin32Display *display)
+{
+ EGLDisplay disp;
+
+ if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
+ {
+ PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT");
+ if (getPlatformDisplay)
+ {
+ EGLint disp_attr[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE};
+
+ disp = getPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE, display->hdc_egl_temp, disp_attr);
+
+ if (disp != EGL_NO_DISPLAY)
+ return disp;
+ }
+ }
+
+ return eglGetDisplay (display->hdc_egl_temp);
+}
+
+#define MAX_EGL_ATTRS 30
+
+static gboolean
+find_eglconfig_for_window (GdkWin32Display *display,
+ EGLConfig *egl_config_out,
+ EGLint *min_swap_interval_out,
+ GError **error)
+{
+ EGLint attrs[MAX_EGL_ATTRS];
+ EGLint count;
+ EGLConfig *configs, chosen_config;
+
+ int i = 0;
+
+ EGLDisplay egl_disp = display->egl_disp;
+
+ attrs[i++] = EGL_CONFORMANT;
+ attrs[i++] = EGL_OPENGL_ES2_BIT;
+ attrs[i++] = EGL_SURFACE_TYPE;
+ attrs[i++] = EGL_WINDOW_BIT;
+
+ attrs[i++] = EGL_COLOR_BUFFER_TYPE;
+ attrs[i++] = EGL_RGB_BUFFER;
+
+ attrs[i++] = EGL_RED_SIZE;
+ attrs[i++] = 1;
+ attrs[i++] = EGL_GREEN_SIZE;
+ attrs[i++] = 1;
+ attrs[i++] = EGL_BLUE_SIZE;
+ attrs[i++] = 1;
+ attrs[i++] = EGL_ALPHA_SIZE;
+ attrs[i++] = 1;
+
+ attrs[i++] = EGL_NONE;
+ g_assert (i < MAX_EGL_ATTRS);
+
+ if (!eglChooseConfig (display->egl_disp, attrs, NULL, 0, &count) || count < 1)
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+ _("No available configurations for the given pixel format"));
+ return FALSE;
+ }
+
+ configs = g_new (EGLConfig, count);
+
+ if (!eglChooseConfig (display->egl_disp, attrs, configs, count, &count) || count < 1)
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+ _("No available configurations for the given pixel format"));
+ return FALSE;
+ }
+
+ /* Pick first valid configuration i guess? */
+ chosen_config = configs[0];
+
+ if (!eglGetConfigAttrib (display->egl_disp, chosen_config,
+ EGL_MIN_SWAP_INTERVAL, min_swap_interval_out))
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ "Could not retrieve the minimum swap interval");
+ g_free (configs);
+ return FALSE;
+ }
+
+ if (egl_config_out != NULL)
+ *egl_config_out = chosen_config;
+
+ g_free (configs);
+
+ return TRUE;
+}
+
+gboolean
+gdk_win32_display_init_egl (GdkDisplay *display,
+ GError **error)
+{
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ int best_idx = 0;
+ EGLDisplay egl_disp;
+
+ if (display_win32->egl_disp != EGL_NO_DISPLAY)
+ return TRUE;
+
+ egl_disp = gdk_win32_get_egl_display (display_win32);
+
+ if (egl_disp == EGL_NO_DISPLAY)
+ return FALSE;
+
+ if (!eglInitialize (egl_disp, NULL, NULL))
+ {
+ eglTerminate (egl_disp);
+ egl_disp = EGL_NO_DISPLAY;
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("No GL implementation is available"));
+ return FALSE;
+ }
+
+ display_win32->egl_disp = egl_disp;
+ display_win32->egl_version = epoxy_egl_version (egl_disp);
+
+ eglBindAPI(EGL_OPENGL_ES_API);
+
+ display_win32->hasEglSurfacelessContext =
+ epoxy_has_egl_extension (egl_disp, "EGL_KHR_surfaceless_context");
+
+ GDK_NOTE (OPENGL,
+ g_print ("EGL API version %d.%d found\n"
+ " - Vendor: %s\n"
+ " - Checked extensions:\n"
+ "\t* EGL_KHR_surfaceless_context: %s\n",
+ display_win32->egl_version / 10,
+ display_win32->egl_version % 10,
+ eglQueryString (display_win32->egl_disp, EGL_VENDOR),
+ display_win32->hasEglSurfacelessContext ? "yes" : "no"));
+
+ return find_eglconfig_for_window (display_win32, &display_win32->egl_config,
+ &display_win32->egl_min_swap_interval, error);
+}
+
+#define N_EGL_ATTRS 16
+
+static EGLContext
+create_egl_context (EGLDisplay display,
+ EGLConfig config,
+ GdkGLContext *share,
+ int flags,
+ int major,
+ int minor,
+ gboolean *is_legacy)
+{
+ EGLContext ctx;
+ EGLint context_attribs[N_EGL_ATTRS];
+ int i = 0;
+
+ /* ANGLE does not support the GL_OES_vertex_array_object extension, so we need to use ES3 directly */
+ context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
+ context_attribs[i++] = 3;
+
+ /* Specify the flags */
+ context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
+ context_attribs[i++] = flags;
+
+ context_attribs[i++] = EGL_NONE;
+ g_assert (i < N_EGL_ATTRS);
+
+ ctx = eglCreateContext (display,
+ config,
+ share != NULL ? GDK_WIN32_GL_CONTEXT_EGL (share)->egl_context
+ : EGL_NO_CONTEXT,
+ context_attribs);
+
+ if (ctx != EGL_NO_CONTEXT)
+ GDK_NOTE (OPENGL, g_message ("Created EGL context[%p]", ctx));
+
+ return ctx;
+}
+
+static gboolean
+gdk_win32_gl_context_egl_realize (GdkGLContext *context,
+ GError **error)
+{
+ GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
+
+ gboolean debug_bit, compat_bit, legacy_bit;
+ gboolean use_es = FALSE;
+ EGLContext egl_context;
+ EGLContext ctx;
+
+ /* request flags and specific versions for core (3.2+) WGL context */
+ int flags = 0;
+ int major = 0;
+ int minor = 0;
+
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+ GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ GdkGLContext *share = gdk_display_get_gl_context (display);
+
+ gdk_gl_context_get_required_version (context, &major, &minor);
+ debug_bit = gdk_gl_context_get_debug_enabled (context);
+ compat_bit = gdk_gl_context_get_forward_compatible (context);
+
+ /*
+ * A legacy context cannot be shared with core profile ones, so this means we
+ * must stick to a legacy context if the shared context is a legacy context
+ */
+
+ /* if GDK_GL_LEGACY is set, we default to a legacy context */
+ legacy_bit = GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ?
+ TRUE :
+ share != NULL && gdk_gl_context_is_legacy (share);
+
+ use_es = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) ||
+ (share != NULL && gdk_gl_context_get_use_es (share));
+
+ if (debug_bit)
+ flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
+ if (compat_bit)
+ flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
+
+ GDK_NOTE (OPENGL, g_message ("Creating EGL context version %d.%d (debug:%s, forward:%s, legacy:%s)",
+ major, minor,
+ debug_bit ? "yes" : "no",
+ compat_bit ? "yes" : "no",
+ legacy_bit ? "yes" : "no"));
+
+ ctx = create_egl_context (display_win32->egl_disp,
+ display_win32->egl_config,
+ share,
+ flags,
+ major,
+ minor,
+ &legacy_bit);
+
+ if (ctx == EGL_NO_CONTEXT)
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("Unable to create a GL context"));
+ return FALSE;
+ }
+
+ GDK_NOTE (OPENGL, g_print ("Created EGL context[%p]\n", ctx));
+
+ context_egl->egl_context = ctx;
+
+ /* We are using GLES here */
+ gdk_gl_context_set_use_es (context, TRUE);
+
+ /* Ensure that any other context is created with a legacy bit set */
+ gdk_gl_context_set_is_legacy (context, legacy_bit);
+
+ return TRUE;
+}
+
+static gboolean
+gdk_win32_gl_context_egl_clear_current (GdkGLContext *context)
+{
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+
+ if (display_win32->egl_disp != EGL_NO_DISPLAY)
+ return eglMakeCurrent (display_win32->egl_disp,
+ EGL_NO_SURFACE,
+ EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+ else
+ return TRUE;
+}
+
+static gboolean
+gdk_win32_gl_context_egl_make_current (GdkGLContext *context,
+ gboolean surfaceless)
+{
+ GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ GdkSurface *surface;
+
+ gboolean do_frame_sync = FALSE;
+
+ EGLSurface egl_surface;
+
+ surface = gdk_gl_context_get_surface (context);
+
+ if (!surfaceless)
+ egl_surface = gdk_win32_surface_get_egl_surface (surface, display_win32->egl_config, FALSE);
+ else
+ {
+ if (display_win32->hasEglSurfacelessContext)
+ egl_surface = EGL_NO_SURFACE;
+ else
+ egl_surface = gdk_win32_surface_get_egl_surface (surface, display_win32->egl_config, TRUE);
+ }
+
+ if (!eglMakeCurrent (display_win32->egl_disp,
+ egl_surface,
+ egl_surface,
+ context_egl->egl_context))
+ return FALSE;
+
+ if (display_win32->egl_min_swap_interval == 0)
+ eglSwapInterval (display_win32->egl_disp, 0);
+ else
+ g_debug ("Can't disable GL swap interval");
+
+ return TRUE;
+}
+
+static void
+gdk_win32_gl_context_egl_begin_frame (GdkDrawContext *draw_context,
+ cairo_region_t *update_area)
+{
+ GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
+ GdkSurface *surface;
+
+ surface = gdk_gl_context_get_surface (context);
+
+ gdk_win32_surface_handle_queued_move_resize (draw_context);
+
+ GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, update_area);
+}
+
+static void
+gdk_win32_gl_context_egl_class_init (GdkWin32GLContextClass *klass)
+{
+ GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS(klass);
+ GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ context_class->realize = gdk_win32_gl_context_egl_realize;
+ context_class->make_current = gdk_win32_gl_context_egl_make_current;
+ context_class->clear_current = gdk_win32_gl_context_egl_clear_current;
+
+ draw_context_class->begin_frame = gdk_win32_gl_context_egl_begin_frame;
+ draw_context_class->end_frame = gdk_win32_gl_context_egl_end_frame;
+
+ gobject_class->dispose = gdk_win32_gl_context_egl_dispose;
+}
+
+static void
+gdk_win32_gl_context_egl_init (GdkWin32GLContextEGL *egl_context)
+{
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-win32.c: Win32 specific OpenGL wrappers
+ *
+ * Copyright © 2014 Emmanuele Bassi
+ * Copyright © 2014 Alexander Larsson
+ * Copyright © 2014 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gdkprivate-win32.h"
+#include "gdksurface-win32.h"
+#include "gdkglcontext-win32.h"
+#include "gdkdisplay-win32.h"
+
+#include "gdkwin32display.h"
+#include "gdkwin32glcontext.h"
+#include "gdkwin32misc.h"
+#include "gdkwin32screen.h"
+#include "gdkwin32surface.h"
+
+#include "gdkglcontext.h"
+#include "gdkprofilerprivate.h"
+#include "gdkinternals.h"
+#include "gdkintl.h"
+#include "gdksurface.h"
+
+#include <cairo.h>
+#include <epoxy/wgl.h>
+
+struct _GdkWin32GLContextWGL
+{
+ GdkWin32GLContext parent_instance;
+
+ HWND wgl_hwnd;
+ HDC wgl_hdc;
+ HGLRC wgl_context;
+ guint do_frame_sync : 1;
+};
+
+typedef struct _GdkWin32GLContextClass GdkWin32GLContextWGLClass;
+
+G_DEFINE_TYPE (GdkWin32GLContextWGL, gdk_win32_gl_context_wgl, GDK_TYPE_WIN32_GL_CONTEXT)
+
+static void
+gdk_win32_gl_context_wgl_dispose (GObject *gobject)
+{
+ GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (gobject);
+
+ if (context_wgl->wgl_context != NULL)
+ {
+ if (wglGetCurrentContext () == context_wgl->wgl_context)
+ wglMakeCurrent (NULL, NULL);
+
+ GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n"));
+
+ wglDeleteContext (context_wgl->wgl_context);
+ context_wgl->wgl_context = NULL;
+
+ ReleaseDC (context_wgl->wgl_hwnd, context_wgl->wgl_hdc);
+ }
+
+ G_OBJECT_CLASS (gdk_win32_gl_context_wgl_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_win32_gl_context_wgl_end_frame (GdkDrawContext *draw_context,
+ cairo_region_t *painted)
+{
+ GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
+ GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+ GdkWin32Display *display = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
+ cairo_rectangle_int_t whole_window;
+
+ GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->end_frame (draw_context, painted);
+
+ gdk_gl_context_make_current (context);
+ whole_window = (GdkRectangle) { 0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface) };
+
+ gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "win32", "swap buffers");
+
+ gboolean can_wait = display->hasWglOMLSyncControl;
+
+ if (context_wgl->do_frame_sync)
+ {
+ glFinish ();
+
+ if (can_wait)
+ {
+ gint64 ust, msc, sbc;
+
+ wglGetSyncValuesOML (context_wgl->wgl_hdc, &ust, &msc, &sbc);
+ wglWaitForMscOML (context_wgl->wgl_hdc,
+ 0,
+ 2,
+ (msc + 1) % 2,
+ &ust, &msc, &sbc);
+ }
+
+ SwapBuffers (context_wgl->wgl_hdc);
+ }
+}
+
+static void
+gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context,
+ cairo_region_t *update_area)
+{
+ GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
+ GdkSurface *surface;
+
+ surface = gdk_gl_context_get_surface (context);
+
+ gdk_win32_surface_handle_queued_move_resize (draw_context);
+
+ GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, update_area);
+}
+
+static int
+gdk_init_dummy_wgl_context (GdkWin32Display *display_win32);
+
+#define PIXEL_ATTRIBUTES 17
+
+static int
+get_wgl_pfd (HDC hdc,
+ PIXELFORMATDESCRIPTOR *pfd,
+ GdkWin32Display *display_win32)
+{
+ int best_pf = 0;
+
+ pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR);
+
+ if (display_win32 != NULL && display_win32->hasWglARBPixelFormat)
+ {
+ UINT num_formats;
+ int colorbits = GetDeviceCaps (hdc, BITSPIXEL);
+ int i = 0;
+ int pixelAttribs[PIXEL_ATTRIBUTES];
+
+ /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
+ HDC hdc_current = wglGetCurrentDC ();
+ HGLRC hglrc_current = wglGetCurrentContext ();
+
+ /* Update PIXEL_ATTRIBUTES above if any groups are added here! */
+ pixelAttribs[i] = WGL_DRAW_TO_WINDOW_ARB;
+ pixelAttribs[i++] = GL_TRUE;
+
+ pixelAttribs[i++] = WGL_SUPPORT_OPENGL_ARB;
+ pixelAttribs[i++] = GL_TRUE;
+
+ pixelAttribs[i++] = WGL_DOUBLE_BUFFER_ARB;
+ pixelAttribs[i++] = GL_TRUE;
+
+ pixelAttribs[i++] = WGL_ACCELERATION_ARB;
+ pixelAttribs[i++] = WGL_FULL_ACCELERATION_ARB;
+
+ pixelAttribs[i++] = WGL_PIXEL_TYPE_ARB;
+ pixelAttribs[i++] = WGL_TYPE_RGBA_ARB;
+
+ pixelAttribs[i++] = WGL_COLOR_BITS_ARB;
+ pixelAttribs[i++] = colorbits;
+
+ /* end of "Update PIXEL_ATTRIBUTES above if any groups are added here!" */
+
+ if (display_win32->hasWglARBmultisample)
+ {
+ pixelAttribs[i++] = WGL_SAMPLE_BUFFERS_ARB;
+ pixelAttribs[i++] = 1;
+
+ pixelAttribs[i++] = WGL_SAMPLES_ARB;
+ pixelAttribs[i++] = 8;
+ }
+
+ pixelAttribs[i++] = 0; /* end of pixelAttribs */
+ best_pf = gdk_init_dummy_wgl_context (display_win32);
+
+ if (!wglMakeCurrent (display_win32->dummy_context_wgl.hdc,
+ display_win32->dummy_context_wgl.hglrc))
+ {
+ wglMakeCurrent (hdc_current, hglrc_current);
+ return 0;
+ }
+
+ wglChoosePixelFormatARB (hdc,
+ pixelAttribs,
+ NULL,
+ 1,
+ &best_pf,
+ &num_formats);
+
+ /* Go back to the HDC that we were using, since we are done with the dummy HDC and GL Context */
+ wglMakeCurrent (hdc_current, hglrc_current);
+ }
+ else
+ {
+ pfd->nVersion = 1;
+ pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
+ pfd->iPixelType = PFD_TYPE_RGBA;
+ pfd->cColorBits = GetDeviceCaps (hdc, BITSPIXEL);
+ pfd->cAlphaBits = 8;
+ pfd->dwLayerMask = PFD_MAIN_PLANE;
+
+ best_pf = ChoosePixelFormat (hdc, pfd);
+ }
+
+ return best_pf;
+}
+
+/* in WGL, for many OpenGL items, we need a dummy WGL context, so create
+ * one and cache it for later use
+ */
+static int
+gdk_init_dummy_wgl_context (GdkWin32Display *display_win32)
+{
+ PIXELFORMATDESCRIPTOR pfd;
+ gboolean set_pixel_format_result = FALSE;
+ int best_idx = 0;
+
+ if (display_win32->dummy_context_wgl.hdc == NULL)
+ display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
+
+ memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR));
+
+ best_idx = get_wgl_pfd (display_win32->dummy_context_wgl.hdc, &pfd, NULL);
+
+ if (best_idx != 0)
+ set_pixel_format_result = SetPixelFormat (display_win32->dummy_context_wgl.hdc,
+ best_idx,
+ &pfd);
+
+ if (best_idx == 0 || !set_pixel_format_result)
+ return 0;
+
+ display_win32->dummy_context_wgl.hglrc =
+ wglCreateContext (display_win32->dummy_context_wgl.hdc);
+
+ if (display_win32->dummy_context_wgl.hglrc == NULL)
+ return 0;
+
+ return best_idx;
+}
+
+gboolean
+gdk_win32_display_init_wgl (GdkDisplay *display,
+ GError **error)
+{
+ int best_idx = 0;
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ HDC hdc;
+
+ if (display_win32->wgl_pixel_format != 0)
+ return TRUE;
+
+ /* acquire and cache dummy Window (HWND & HDC) and
+ * dummy GL Context, it is used to query functions
+ * and used for other stuff as well
+ */
+ best_idx = gdk_init_dummy_wgl_context (display_win32);
+ hdc = display_win32->dummy_context_wgl.hdc;
+
+ if (best_idx == 0 ||
+ !wglMakeCurrent (hdc, display_win32->dummy_context_wgl.hglrc))
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("No GL implementation is available"));
+
+ return FALSE;
+ }
+
+ display_win32->wgl_pixel_format = best_idx;
+ display_win32->gl_version = epoxy_gl_version ();
+
+ display_win32->hasWglARBCreateContext =
+ epoxy_has_wgl_extension (hdc, "WGL_ARB_create_context");
+ display_win32->hasWglEXTSwapControl =
+ epoxy_has_wgl_extension (hdc, "WGL_EXT_swap_control");
+ display_win32->hasWglOMLSyncControl =
+ epoxy_has_wgl_extension (hdc, "WGL_OML_sync_control");
+ display_win32->hasWglARBPixelFormat =
+ epoxy_has_wgl_extension (hdc, "WGL_ARB_pixel_format");
+ display_win32->hasWglARBmultisample =
+ epoxy_has_wgl_extension (hdc, "WGL_ARB_multisample");
+
+ GDK_NOTE (OPENGL,
+ g_print ("WGL API version %d.%d found\n"
+ " - Vendor: %s\n"
+ " - Checked extensions:\n"
+ "\t* WGL_ARB_pixel_format: %s\n"
+ "\t* WGL_ARB_create_context: %s\n"
+ "\t* WGL_EXT_swap_control: %s\n"
+ "\t* WGL_OML_sync_control: %s\n"
+ "\t* WGL_ARB_multisample: %s\n",
+ display_win32->gl_version / 10,
+ display_win32->gl_version % 10,
+ glGetString (GL_VENDOR),
+ display_win32->hasWglARBPixelFormat ? "yes" : "no",
+ display_win32->hasWglARBCreateContext ? "yes" : "no",
+ display_win32->hasWglEXTSwapControl ? "yes" : "no",
+ display_win32->hasWglOMLSyncControl ? "yes" : "no",
+ display_win32->hasWglARBmultisample ? "yes" : "no"));
+
+ wglMakeCurrent (NULL, NULL);
+
+ return TRUE;
+}
+
+/* Setup the legacy context after creating it */
+static gboolean
+ensure_legacy_wgl_context (HDC hdc,
+ HGLRC hglrc_legacy,
+ GdkGLContext *share)
+{
+ GdkWin32GLContextWGL *context_wgl;
+
+ if (!wglMakeCurrent (hdc, hglrc_legacy))
+ return FALSE;
+
+ if (share != NULL)
+ {
+ context_wgl = GDK_WIN32_GL_CONTEXT_WGL (share);
+
+ return wglShareLists (hglrc_legacy, context_wgl->wgl_context);
+ }
+
+ return TRUE;
+}
+
+static HGLRC
+create_wgl_context_with_attribs (HDC hdc,
+ HGLRC hglrc_base,
+ GdkGLContext *share,
+ int flags,
+ int major,
+ int minor,
+ gboolean *is_legacy)
+{
+ HGLRC hglrc;
+ GdkWin32GLContextWGL *context_wgl;
+
+ /* if we have wglCreateContextAttribsARB(), create a
+ * context with the compatibility profile if a legacy
+ * context is requested, or when we go into fallback mode
+ */
+ int profile = *is_legacy ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :
+ WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+
+ int attribs[] = {
+ WGL_CONTEXT_PROFILE_MASK_ARB, profile,
+ WGL_CONTEXT_MAJOR_VERSION_ARB, *is_legacy ? 3 : major,
+ WGL_CONTEXT_MINOR_VERSION_ARB, *is_legacy ? 0 : minor,
+ WGL_CONTEXT_FLAGS_ARB, flags,
+ 0
+ };
+
+ if (share != NULL)
+ context_wgl = GDK_WIN32_GL_CONTEXT_WGL (share);
+
+ hglrc = wglCreateContextAttribsARB (hdc,
+ share != NULL ? context_wgl->wgl_context : NULL,
+ attribs);
+
+ return hglrc;
+}
+
+static HGLRC
+create_wgl_context (HDC hdc,
+ GdkGLContext *share,
+ int flags,
+ int major,
+ int minor,
+ gboolean *is_legacy,
+ gboolean hasWglARBCreateContext)
+{
+ /* We need a legacy context for *all* cases */
+ HGLRC hglrc_base = wglCreateContext (hdc);
+ gboolean success = TRUE;
+
+ /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
+ HDC hdc_current = wglGetCurrentDC ();
+ HGLRC hglrc_current = wglGetCurrentContext ();
+
+ /* if we have no wglCreateContextAttribsARB(), return the legacy context when all is set */
+ if (*is_legacy && !hasWglARBCreateContext)
+ {
+ if (ensure_legacy_wgl_context (hdc, hglrc_base, share))
+ {
+ wglMakeCurrent (hdc_current, hglrc_current);
+ return hglrc_base;
+ }
+
+ success = FALSE;
+ goto gl_fail;
+ }
+ else
+ {
+ HGLRC hglrc = NULL;
+
+ if (!wglMakeCurrent (hdc, hglrc_base))
+ {
+ success = FALSE;
+ goto gl_fail;
+ }
+
+ /*
+ * We need a Core GL 4.1 context in order to use the GL support in
+ * the GStreamer media widget backend, but wglCreateContextAttribsARB()
+ * may only give us the GL context version that we ask for here, and
+ * nothing more. So, if we are asking for a pre-GL 4.1 context,
+ * try to ask for a 4.1 context explicitly first. If that is not supported,
+ * then we fall back to whatever version that we were asking for (or, even a
+ * legacy context if that fails), at a price of not able to have GL support
+ * for the media GStreamer backend.
+ */
+ if (major < 4 || (major == 4 && minor < 1))
+ hglrc = create_wgl_context_with_attribs (hdc,
+ hglrc_base,
+ share,
+ flags,
+ 4,
+ 1,
+ is_legacy);
+
+ if (hglrc == NULL)
+ hglrc = create_wgl_context_with_attribs (hdc,
+ hglrc_base,
+ share,
+ flags,
+ major,
+ minor,
+ is_legacy);
+
+ /* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
+ if (hglrc == NULL)
+ {
+ if (!(*is_legacy))
+ {
+ /* If we aren't using a legacy context in the beginning, try again with a compatibility profile 3.0 context */
+ hglrc = create_wgl_context_with_attribs (hdc,
+ hglrc_base,
+ share,
+ flags,
+ 0, 0,
+ is_legacy);
+
+ *is_legacy = TRUE;
+ }
+
+ if (hglrc == NULL)
+ {
+ if (!ensure_legacy_wgl_context (hdc, hglrc_base, share))
+ success = FALSE;
+ }
+
+ if (success)
+ GDK_NOTE (OPENGL, g_print ("Using legacy context as fallback\n"));
+ }
+
+gl_fail:
+
+ if (!success)
+ {
+ wglMakeCurrent (NULL, NULL);
+ wglDeleteContext (hglrc_base);
+ return NULL;
+ }
+
+ wglMakeCurrent (hdc_current, hglrc_current);
+
+ if (hglrc != NULL)
+ {
+ wglDeleteContext (hglrc_base);
+ return hglrc;
+ }
+
+ return hglrc_base;
+ }
+}
+
+static gboolean
+set_wgl_pixformat_for_hdc (HDC hdc,
+ int *best_idx,
+ GdkWin32Display *display_win32)
+{
+ gboolean already_checked = TRUE;
+ *best_idx = GetPixelFormat (hdc);
+
+ /* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
+ * one single time per window HDC
+ */
+ if (*best_idx == 0)
+ {
+ PIXELFORMATDESCRIPTOR pfd;
+ gboolean set_pixel_format_result = FALSE;
+
+ GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
+ already_checked = FALSE;
+ *best_idx = get_wgl_pfd (hdc, &pfd, display_win32);
+
+ if (*best_idx != 0)
+ set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd);
+
+ /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */
+ if (*best_idx == 0 || !set_pixel_format_result)
+ return FALSE;
+ }
+
+ GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
+
+ return TRUE;
+}
+
+static gboolean
+gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
+ GError **error)
+{
+ GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
+
+ gboolean debug_bit, compat_bit, legacy_bit;
+
+ /* request flags and specific versions for core (3.2+) WGL context */
+ int flags = 0;
+ int major = 0;
+ int minor = 0;
+ HGLRC hglrc;
+ int pixel_format;
+ HDC hdc;
+ HWND hwnd;
+
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ GdkGLContext *share = gdk_display_get_gl_context (display);
+
+ gdk_gl_context_get_required_version (context, &major, &minor);
+ debug_bit = gdk_gl_context_get_debug_enabled (context);
+ compat_bit = gdk_gl_context_get_forward_compatible (context);
+
+ if (surface != NULL)
+ {
+ hwnd = GDK_SURFACE_HWND (surface);
+ context_wgl->wgl_hdc = hdc = GetDC (hwnd);
+ }
+ else
+ {
+ hwnd = display_win32->hwnd;
+ hdc = display_win32->dummy_context_wgl.hdc;
+ }
+
+ /*
+ * A legacy context cannot be shared with core profile ones, so this means we
+ * must stick to a legacy context if the shared context is a legacy context
+ */
+ legacy_bit = GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ?
+ TRUE :
+ share != NULL && gdk_gl_context_is_legacy (share);
+
+ if (!set_wgl_pixformat_for_hdc (hdc,
+ &pixel_format,
+ display_win32))
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+ _("No available configurations for the given pixel format"));
+
+ return FALSE;
+ }
+
+ /* if there isn't wglCreateContextAttribsARB() on WGL, use a legacy context */
+ if (!legacy_bit)
+ legacy_bit = !display_win32->hasWglARBCreateContext;
+ if (debug_bit)
+ flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
+ if (compat_bit)
+ flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+
+ GDK_NOTE (OPENGL,
+ g_print ("Creating %s WGL context (version:%d.%d, debug:%s, forward:%s, legacy: %s)\n",
+ compat_bit ? "core" : "compat",
+ major,
+ minor,
+ debug_bit ? "yes" : "no",
+ compat_bit ? "yes" : "no",
+ legacy_bit ? "yes" : "no"));
+
+ hglrc = create_wgl_context (hdc,
+ share,
+ flags,
+ major,
+ minor,
+ &legacy_bit,
+ display_win32->hasWglARBCreateContext);
+
+ if (hglrc == NULL)
+ {
+ g_set_error_literal (error, GDK_GL_ERROR,
+ GDK_GL_ERROR_NOT_AVAILABLE,
+ _("Unable to create a GL context"));
+ return FALSE;
+ }
+
+ GDK_NOTE (OPENGL,
+ g_print ("Created WGL context[%p], pixel_format=%d\n",
+ hglrc,
+ pixel_format));
+
+ context_wgl->wgl_context = hglrc;
+
+ /* No GLES, WGL does not support using EGL contexts */
+ gdk_gl_context_set_use_es (context, FALSE);
+
+ /* Ensure that any other context is created with a legacy bit set */
+ gdk_gl_context_set_is_legacy (context, legacy_bit);
+
+ return TRUE;
+}
+
+static gboolean
+gdk_win32_gl_context_wgl_clear_current (GdkGLContext *context)
+{
+ return wglMakeCurrent (NULL, NULL);
+}
+
+static gboolean
+gdk_win32_gl_context_wgl_make_current (GdkGLContext *context,
+ gboolean surfaceless)
+{
+ GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
+ GdkDisplay *display = gdk_gl_context_get_display (context);
+ GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
+ GdkSurface *surface;
+ HDC hdc;
+
+ if (surfaceless)
+ hdc = display_win32->dummy_context_wgl.hdc;
+ else
+ hdc = context_wgl->wgl_hdc;
+
+ if (!wglMakeCurrent (hdc, context_wgl->wgl_context))
+ return FALSE;
+
+ if (!surfaceless && display_win32->hasWglEXTSwapControl)
+ {
+ gboolean do_frame_sync = FALSE;
+ GdkSurface *surface = gdk_gl_context_get_surface (context);
+
+ /* If there is compositing there is no particular need to delay
+ * the swap when drawing on the offscreen, rendering to the screen
+ * happens later anyway, and its up to the compositor to sync that
+ * to the vblank. */
+ do_frame_sync = ! gdk_display_is_composited (display);
+
+ if (do_frame_sync != context_wgl->do_frame_sync)
+ {
+ context_wgl->do_frame_sync = do_frame_sync;
+
+ wglSwapIntervalEXT (do_frame_sync ? 1 : 0);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *klass)
+{
+ GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+ GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ context_class->realize = gdk_win32_gl_context_wgl_realize;
+ context_class->make_current = gdk_win32_gl_context_wgl_make_current;
+ context_class->clear_current = gdk_win32_gl_context_wgl_clear_current;
+
+ draw_context_class->begin_frame = gdk_win32_gl_context_wgl_begin_frame;
+ draw_context_class->end_frame = gdk_win32_gl_context_wgl_end_frame;
+ gobject_class->dispose = gdk_win32_gl_context_wgl_dispose;
+}
+
+static void
+gdk_win32_gl_context_wgl_init (GdkWin32GLContextWGL *wgl_context)
+{
+}
+
+void gdk_win32_gl_context_wgl_bind_surface (GdkWin32GLContextWGL *wgl_context,
+ GdkWin32Surface *impl)
+{
+ wgl_context->wgl_hwnd = impl->handle;
+ wgl_context->wgl_hdc = GetDC (impl->handle);
+}
+
+/**
+ * gdk_win32_display_get_wgl_version:
+ * @display: a `GdkDisplay`
+ * @major: (out): return location for the WGL major version
+ * @minor: (out): return location for the WGL minor version
+ *
+ * Retrieves the version of the WGL implementation.
+ *
+ * Returns: %TRUE if WGL is available
+ */
+gboolean
+gdk_win32_display_get_wgl_version (GdkDisplay *display,
+ int *major,
+ int *minor)
+{
+ GdkWin32Display *display_win32;
+ g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+ if (!GDK_IS_WIN32_DISPLAY (display))
+ return FALSE;
+
+ display_win32 = GDK_WIN32_DISPLAY (display);
+ if (display_win32->wgl_pixel_format == 0)
+ return FALSE;
+
+ if (major != NULL)
+ *major = display_win32->gl_version / 10;
+ if (minor != NULL)
+ *minor = display_win32->gl_version % 10;
+
+ return TRUE;
+}
# include <epoxy/egl.h>
#endif
-G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT)
-
-static void
-_gdk_win32_gl_context_dispose (GObject *gobject)
-{
- GdkGLContext *context = GDK_GL_CONTEXT (gobject);
- GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (gobject);
- GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context));
- GdkSurface *surface = gdk_gl_context_get_surface (context);
-
- if (display_win32 != NULL)
- {
- if (display_win32->have_wgl)
- {
- if (wglGetCurrentContext () == context_win32->hglrc)
- wglMakeCurrent (NULL, NULL);
-
- GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n"));
-
- wglDeleteContext (context_win32->hglrc);
- context_win32->hglrc = NULL;
- }
-
-#ifdef GDK_WIN32_ENABLE_EGL
- else if (display_win32->have_egl)
- {
- if (eglGetCurrentContext () == context_win32->egl_context)
- eglMakeCurrent(display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
-
- GDK_NOTE (OPENGL, g_message ("Destroying EGL (ANGLE) context"));
-
- eglDestroyContext (display_win32->egl_disp,
- context_win32->egl_context);
- context_win32->egl_context = EGL_NO_CONTEXT;
- }
-#endif
- }
-
- G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject);
-}
-
-#ifdef GDK_WIN32_ENABLE_EGL
-static gboolean
-_get_is_egl_force_redraw (GdkSurface *surface)
-{
- /* We only need to call gdk_window_invalidate_rect () if necessary */
- if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context))
- {
- GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
-
- return impl->egl_force_redraw_all;
- }
- return FALSE;
-}
-
-static void
-_reset_egl_force_redraw (GdkSurface *surface)
-{
- if (surface->gl_paint_context != NULL && gdk_gl_context_get_use_es (surface->gl_paint_context))
- {
- GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
-
- if (impl->egl_force_redraw_all)
- impl->egl_force_redraw_all = FALSE;
- }
-}
-#endif
-
-static void
-gdk_win32_gl_context_end_frame (GdkDrawContext *draw_context,
- cairo_region_t *painted)
-{
- GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
- GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
- GdkSurface *surface = gdk_gl_context_get_surface (context);
- GdkWin32Display *display = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
- cairo_rectangle_int_t whole_window;
-
- GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_parent_class)->end_frame (draw_context, painted);
-
- gdk_gl_context_make_current (context);
- whole_window = (GdkRectangle) { 0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface) };
-
- if (!gdk_gl_context_get_use_es (context))
- {
- gboolean can_wait = display->hasWglOMLSyncControl;
-
- if (context_win32->do_frame_sync)
- {
- glFinish ();
-
- if (can_wait)
- {
- gint64 ust, msc, sbc;
-
- wglGetSyncValuesOML (context_win32->gl_hdc, &ust, &msc, &sbc);
- wglWaitForMscOML (context_win32->gl_hdc,
- 0,
- 2,
- (msc + 1) % 2,
- &ust, &msc, &sbc);
- }
- }
-
- SwapBuffers (context_win32->gl_hdc);
- }
-#ifdef GDK_WIN32_ENABLE_EGL
- else
- {
- EGLSurface egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE);
- gboolean force_egl_redraw_all = _get_is_egl_force_redraw (surface);
-
- if (force_egl_redraw_all)
- {
- GdkRectangle rect = {0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface)};
-
- /* We need to do gdk_window_invalidate_rect() so that we don't get glitches after maximizing or
- * restoring or using aerosnap
- */
- gdk_surface_invalidate_rect (surface, &rect);
- _reset_egl_force_redraw (surface);
- }
-
- eglSwapBuffers (display->egl_disp, egl_surface);
- }
-#endif
-}
-
-static void
-gdk_win32_gl_context_begin_frame (GdkDrawContext *draw_context,
- cairo_region_t *update_area)
-{
- GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
- GdkSurface *surface;
-
- surface = gdk_gl_context_get_surface (context);
-
- gdk_win32_surface_handle_queued_move_resize (draw_context);
-
- GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_parent_class)->begin_frame (draw_context, update_area);
-}
-
-typedef struct
-{
- ATOM wc_atom;
- HWND hwnd;
- HDC hdc;
- HGLRC hglrc;
- gboolean inited;
-} GdkWGLDummy;
-
-static void
-_destroy_dummy_gl_context (GdkWGLDummy dummy)
-{
- if (dummy.hglrc != NULL)
- {
- wglDeleteContext (dummy.hglrc);
- dummy.hglrc = NULL;
- }
- if (dummy.hdc != NULL)
- {
- DeleteDC (dummy.hdc);
- dummy.hdc = NULL;
- }
- if (dummy.hwnd != NULL)
- {
- DestroyWindow (dummy.hwnd);
- dummy.hwnd = NULL;
- }
- if (dummy.wc_atom != 0)
- {
- UnregisterClass (MAKEINTATOM (dummy.wc_atom), GetModuleHandle (NULL));
- dummy.wc_atom = 0;
- }
- dummy.inited = FALSE;
-}
-
-/* Yup, we need to create a dummy window for the dummy WGL context */
-static void
-_get_dummy_window_hwnd (GdkWGLDummy *dummy)
-{
- WNDCLASSEX dummy_wc;
-
- memset (&dummy_wc, 0, sizeof (WNDCLASSEX));
-
- dummy_wc.cbSize = sizeof( WNDCLASSEX );
- dummy_wc.style = CS_OWNDC;
- dummy_wc.lpfnWndProc = (WNDPROC) DefWindowProc;
- dummy_wc.cbClsExtra = 0;
- dummy_wc.cbWndExtra = 0;
- dummy_wc.hInstance = GetModuleHandle( NULL );
- dummy_wc.hIcon = 0;
- dummy_wc.hCursor = NULL;
- dummy_wc.hbrBackground = 0;
- dummy_wc.lpszMenuName = 0;
- dummy_wc.lpszClassName = "dummy";
- dummy_wc.hIconSm = 0;
-
- dummy->wc_atom = RegisterClassEx (&dummy_wc);
-
- dummy->hwnd =
- CreateWindowEx (WS_EX_APPWINDOW,
- MAKEINTATOM (dummy->wc_atom),
- "",
- WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- GetModuleHandle (NULL),
- NULL);
-}
-
-static int
-_gdk_init_dummy_context (GdkWGLDummy *dummy);
-
-#define PIXEL_ATTRIBUTES 17
-
-static int
-_get_wgl_pfd (HDC hdc,
- PIXELFORMATDESCRIPTOR *pfd,
- GdkWin32Display *display)
-{
- int best_pf = 0;
-
- pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR);
-
- if (display != NULL && display->hasWglARBPixelFormat)
- {
- GdkWGLDummy dummy;
- UINT num_formats;
- int colorbits = GetDeviceCaps (hdc, BITSPIXEL);
- guint extra_fields = 1;
- int i = 0;
- int pixelAttribs[PIXEL_ATTRIBUTES];
-
- /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
- HDC hdc_current = wglGetCurrentDC ();
- HGLRC hglrc_current = wglGetCurrentContext ();
-
- if (display->hasWglARBmultisample)
- {
- /* 2 pairs of values needed for multisampling/AA support */
- extra_fields += 2 * 2;
- }
-
- /* Update PIXEL_ATTRIBUTES above if any groups are added here! */
- /* one group contains a value pair for both pixelAttribs and pixelAttribsNoAlpha */
- pixelAttribs[i] = WGL_DRAW_TO_WINDOW_ARB;
- pixelAttribs[i++] = GL_TRUE;
-
- pixelAttribs[i++] = WGL_SUPPORT_OPENGL_ARB;
- pixelAttribs[i++] = GL_TRUE;
-
- pixelAttribs[i++] = WGL_DOUBLE_BUFFER_ARB;
- pixelAttribs[i++] = GL_TRUE;
-
- pixelAttribs[i++] = WGL_ACCELERATION_ARB;
- pixelAttribs[i++] = WGL_FULL_ACCELERATION_ARB;
-
- pixelAttribs[i++] = WGL_PIXEL_TYPE_ARB;
- pixelAttribs[i++] = WGL_TYPE_RGBA_ARB;
-
- pixelAttribs[i++] = WGL_COLOR_BITS_ARB;
- pixelAttribs[i++] = colorbits;
-
- /* end of "Update PIXEL_ATTRIBUTES above if any groups are added here!" */
-
- if (display->hasWglARBmultisample)
- {
- pixelAttribs[i++] = WGL_SAMPLE_BUFFERS_ARB;
- pixelAttribs[i++] = 1;
-
- pixelAttribs[i++] = WGL_SAMPLES_ARB;
- pixelAttribs[i++] = 8;
- }
-
- pixelAttribs[i++] = 0; /* end of pixelAttribs */
-
- memset (&dummy, 0, sizeof (GdkWGLDummy));
-
- /* acquire and cache dummy Window (HWND & HDC) and
- * dummy GL Context, we need it for wglChoosePixelFormatARB()
- */
- best_pf = _gdk_init_dummy_context (&dummy);
-
- if (best_pf == 0 || !wglMakeCurrent (dummy.hdc, dummy.hglrc))
- {
- wglMakeCurrent (hdc_current, hglrc_current);
- return 0;
- }
-
- wglChoosePixelFormatARB (hdc,
- pixelAttribs,
- NULL,
- 1,
- &best_pf,
- &num_formats);
-
- /* Go back to the HDC that we were using, since we are done with the dummy HDC and GL Context */
- wglMakeCurrent (hdc_current, hglrc_current);
- _destroy_dummy_gl_context (dummy);
- }
- else
- {
- pfd->nVersion = 1;
- pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
- pfd->iPixelType = PFD_TYPE_RGBA;
- pfd->cColorBits = GetDeviceCaps (hdc, BITSPIXEL);
- pfd->cAlphaBits = 8;
- pfd->dwLayerMask = PFD_MAIN_PLANE;
-
- best_pf = ChoosePixelFormat (hdc, pfd);
- }
-
- return best_pf;
-}
-
-/* in WGL, for many OpenGL items, we need a dummy WGL context, so create
- * one and cache it for later use
- */
-static int
-_gdk_init_dummy_context (GdkWGLDummy *dummy)
-{
- PIXELFORMATDESCRIPTOR pfd;
- gboolean set_pixel_format_result = FALSE;
- int best_idx = 0;
-
- _get_dummy_window_hwnd (dummy);
-
- dummy->hdc = GetDC (dummy->hwnd);
- memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR));
-
- best_idx = _get_wgl_pfd (dummy->hdc, &pfd, NULL);
-
- if (best_idx != 0)
- set_pixel_format_result = SetPixelFormat (dummy->hdc,
- best_idx,
- &pfd);
-
- if (best_idx == 0 || !set_pixel_format_result)
- return 0;
-
- dummy->hglrc = wglCreateContext (dummy->hdc);
- if (dummy->hglrc == NULL)
- return 0;
-
- dummy->inited = TRUE;
-
- return best_idx;
-}
-
-#ifdef GDK_WIN32_ENABLE_EGL
-
-#ifndef EGL_PLATFORM_ANGLE_ANGLE
-#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
-#endif
-
-#ifndef EGL_PLATFORM_ANGLE_TYPE_ANGLE
-#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
-#endif
-
-#ifndef EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
-#endif
-
-static EGLDisplay
-_gdk_win32_get_egl_display (GdkWin32Display *display)
-{
- EGLDisplay disp;
-
- if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
- {
- PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT");
- if (getPlatformDisplay)
- {
- EGLint disp_attr[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE};
-
- disp = getPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE, display->hdc_egl_temp, disp_attr);
-
- if (disp != EGL_NO_DISPLAY)
- return disp;
- }
- }
- return eglGetDisplay (display->hdc_egl_temp);
-}
-#endif
-
-static gboolean
-_gdk_win32_display_init_gl (GdkDisplay *display)
-{
- GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
- int best_idx = 0;
-
- gboolean disable_wgl = FALSE;
-
-#ifdef GDK_WIN32_ENABLE_EGL
- EGLDisplay egl_disp;
-
- disable_wgl = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) ||
- display_win32->running_on_arm64;
-#endif
-
- if (display_win32->have_wgl
-#ifdef GDK_WIN32_ENABLE_EGL
- || display_win32->have_egl
-#endif
- )
- return TRUE;
-
- if (!disable_wgl)
- {
- GdkWGLDummy dummy;
- memset (&dummy, 0, sizeof (GdkWGLDummy));
-
- /* acquire and cache dummy Window (HWND & HDC) and
- * dummy GL Context, it is used to query functions
- * and used for other stuff as well
- */
- best_idx = _gdk_init_dummy_context (&dummy);
-
- if (best_idx == 0 || !wglMakeCurrent (dummy.hdc, dummy.hglrc))
- return FALSE;
-
- display_win32->have_wgl = TRUE;
- display_win32->gl_version = epoxy_gl_version ();
-
- display_win32->hasWglARBCreateContext =
- epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_create_context");
- display_win32->hasWglEXTSwapControl =
- epoxy_has_wgl_extension (dummy.hdc, "WGL_EXT_swap_control");
- display_win32->hasWglOMLSyncControl =
- epoxy_has_wgl_extension (dummy.hdc, "WGL_OML_sync_control");
- display_win32->hasWglARBPixelFormat =
- epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_pixel_format");
- display_win32->hasWglARBmultisample =
- epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_multisample");
-
- GDK_NOTE (OPENGL,
- g_print ("WGL API version %d.%d found\n"
- " - Vendor: %s\n"
- " - Checked extensions:\n"
- "\t* WGL_ARB_pixel_format: %s\n"
- "\t* WGL_ARB_create_context: %s\n"
- "\t* WGL_EXT_swap_control: %s\n"
- "\t* WGL_OML_sync_control: %s\n"
- "\t* WGL_ARB_multisample: %s\n",
- display_win32->gl_version / 10,
- display_win32->gl_version % 10,
- glGetString (GL_VENDOR),
- display_win32->hasWglARBPixelFormat ? "yes" : "no",
- display_win32->hasWglARBCreateContext ? "yes" : "no",
- display_win32->hasWglEXTSwapControl ? "yes" : "no",
- display_win32->hasWglOMLSyncControl ? "yes" : "no",
- display_win32->hasWglARBmultisample ? "yes" : "no"));
-
- wglMakeCurrent (NULL, NULL);
- _destroy_dummy_gl_context (dummy);
- }
-#ifdef GDK_WIN32_ENABLE_EGL
- else
- {
- egl_disp = _gdk_win32_get_egl_display (display_win32);
-
- if (egl_disp == EGL_NO_DISPLAY || !eglInitialize (egl_disp, NULL, NULL))
- {
- if (egl_disp != EGL_NO_DISPLAY)
- {
- eglTerminate (egl_disp);
- egl_disp = EGL_NO_DISPLAY;
- }
-
- return FALSE;
- }
-
-
- display_win32->egl_disp = egl_disp;
- display_win32->have_egl = TRUE;
- display_win32->egl_version = epoxy_egl_version (egl_disp);
-
- eglBindAPI(EGL_OPENGL_ES_API);
-
- display_win32->hasEglSurfacelessContext =
- epoxy_has_egl_extension (egl_disp, "EGL_KHR_surfaceless_context");
-
- GDK_NOTE (OPENGL,
- g_print ("EGL API version %d.%d found\n"
- " - Vendor: %s\n"
- " - Checked extensions:\n"
- "\t* EGL_KHR_surfaceless_context: %s\n",
- display_win32->egl_version / 10,
- display_win32->egl_version % 10,
- eglQueryString (display_win32->egl_disp, EGL_VENDOR),
- display_win32->hasEglSurfacelessContext ? "yes" : "no"));
- }
-#endif
-
- return TRUE;
-}
-
-/* Setup the legacy context after creating it */
-static gboolean
-_ensure_legacy_gl_context (HDC hdc,
- HGLRC hglrc_legacy,
- GdkGLContext *share)
-{
- GdkWin32GLContext *context_win32;
-
- if (!wglMakeCurrent (hdc, hglrc_legacy))
- return FALSE;
-
- if (share != NULL)
- {
- context_win32 = GDK_WIN32_GL_CONTEXT (share);
-
- return wglShareLists (hglrc_legacy, context_win32->hglrc);
- }
-
- return TRUE;
-}
-
-static HGLRC
-_create_gl_context_with_attribs (HDC hdc,
- HGLRC hglrc_base,
- GdkGLContext *share,
- int flags,
- int major,
- int minor,
- gboolean *is_legacy)
-{
- HGLRC hglrc;
- GdkWin32GLContext *context_win32;
-
- /* if we have wglCreateContextAttribsARB(), create a
- * context with the compatibility profile if a legacy
- * context is requested, or when we go into fallback mode
- */
- int profile = *is_legacy ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :
- WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
-
- int attribs[] = {
- WGL_CONTEXT_PROFILE_MASK_ARB, profile,
- WGL_CONTEXT_MAJOR_VERSION_ARB, *is_legacy ? 3 : major,
- WGL_CONTEXT_MINOR_VERSION_ARB, *is_legacy ? 0 : minor,
- WGL_CONTEXT_FLAGS_ARB, flags,
- 0
- };
-
- if (share != NULL)
- context_win32 = GDK_WIN32_GL_CONTEXT (share);
-
- hglrc = wglCreateContextAttribsARB (hdc,
- share != NULL ? context_win32->hglrc : NULL,
- attribs);
-
- return hglrc;
-}
-
-static HGLRC
-_create_gl_context (HDC hdc,
- GdkGLContext *share,
- int flags,
- int major,
- int minor,
- gboolean *is_legacy,
- gboolean hasWglARBCreateContext)
-{
- /* We need a legacy context for *all* cases */
- HGLRC hglrc_base = wglCreateContext (hdc);
- gboolean success = TRUE;
-
- /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
- HDC hdc_current = wglGetCurrentDC ();
- HGLRC hglrc_current = wglGetCurrentContext ();
-
- /* if we have no wglCreateContextAttribsARB(), return the legacy context when all is set */
- if (*is_legacy && !hasWglARBCreateContext)
- {
- if (_ensure_legacy_gl_context (hdc, hglrc_base, share))
- {
- wglMakeCurrent (hdc_current, hglrc_current);
- return hglrc_base;
- }
-
- success = FALSE;
- goto gl_fail;
- }
- else
- {
- HGLRC hglrc = NULL;
-
- if (!wglMakeCurrent (hdc, hglrc_base))
- {
- success = FALSE;
- goto gl_fail;
- }
-
- /*
- * We need a Core GL 4.1 context in order to use the GL support in
- * the GStreamer media widget backend, but wglCreateContextAttribsARB()
- * may only give us the GL context version that we ask for here, and
- * nothing more. So, if we are asking for a pre-GL 4.1 context,
- * try to ask for a 4.1 context explicitly first. If that is not supported,
- * then we fall back to whatever version that we were asking for (or, even a
- * legacy context if that fails), at a price of not able to have GL support
- * for the media GStreamer backend.
- */
- if (major < 4 || (major == 4 && minor < 1))
- hglrc = _create_gl_context_with_attribs (hdc,
- hglrc_base,
- share,
- flags,
- 4,
- 1,
- is_legacy);
-
- if (hglrc == NULL)
- hglrc = _create_gl_context_with_attribs (hdc,
- hglrc_base,
- share,
- flags,
- major,
- minor,
- is_legacy);
-
- /* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
- if (hglrc == NULL)
- {
- if (!(*is_legacy))
- {
- /* If we aren't using a legacy context in the beginning, try again with a compatibility profile 3.0 context */
- hglrc = _create_gl_context_with_attribs (hdc,
- hglrc_base,
- share,
- flags,
- 0, 0,
- is_legacy);
-
- *is_legacy = TRUE;
- }
-
- if (hglrc == NULL)
- {
- if (!_ensure_legacy_gl_context (hdc, hglrc_base, share))
- success = FALSE;
- }
-
- if (success)
- GDK_NOTE (OPENGL, g_print ("Using legacy context as fallback\n"));
- }
-
-gl_fail:
-
- if (!success)
- {
- wglMakeCurrent (NULL, NULL);
- wglDeleteContext (hglrc_base);
- return NULL;
- }
-
- wglMakeCurrent (hdc_current, hglrc_current);
-
- if (hglrc != NULL)
- {
- wglDeleteContext (hglrc_base);
- return hglrc;
- }
-
- return hglrc_base;
- }
-}
-
-static gboolean
-_set_pixformat_for_hdc (HDC hdc,
- int *best_idx,
- GdkWin32Display *display)
-{
- gboolean already_checked = TRUE;
- *best_idx = GetPixelFormat (hdc);
-
- /* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
- * one single time per window HDC
- */
- if (*best_idx == 0)
- {
- PIXELFORMATDESCRIPTOR pfd;
- gboolean set_pixel_format_result = FALSE;
-
- GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
- already_checked = FALSE;
- *best_idx = _get_wgl_pfd (hdc, &pfd, display);
-
- if (*best_idx != 0)
- set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd);
-
- /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */
- if (*best_idx == 0 || !set_pixel_format_result)
- return FALSE;
- }
-
- GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
-
- return TRUE;
-}
-
-#ifdef GDK_WIN32_ENABLE_EGL
-
-#define MAX_EGL_ATTRS 30
-
-static gboolean
-find_eglconfig_for_window (GdkWin32Display *display,
- EGLConfig *egl_config_out,
- EGLint *min_swap_interval_out,
- GError **error)
-{
- EGLint attrs[MAX_EGL_ATTRS];
- EGLint count;
- EGLConfig *configs, chosen_config;
-
- int i = 0;
-
- EGLDisplay egl_disp = display->egl_disp;
-
- attrs[i++] = EGL_CONFORMANT;
- attrs[i++] = EGL_OPENGL_ES2_BIT;
- attrs[i++] = EGL_SURFACE_TYPE;
- attrs[i++] = EGL_WINDOW_BIT;
-
- attrs[i++] = EGL_COLOR_BUFFER_TYPE;
- attrs[i++] = EGL_RGB_BUFFER;
-
- attrs[i++] = EGL_RED_SIZE;
- attrs[i++] = 1;
- attrs[i++] = EGL_GREEN_SIZE;
- attrs[i++] = 1;
- attrs[i++] = EGL_BLUE_SIZE;
- attrs[i++] = 1;
- attrs[i++] = EGL_ALPHA_SIZE;
- attrs[i++] = 1;
-
- attrs[i++] = EGL_NONE;
- g_assert (i < MAX_EGL_ATTRS);
-
- if (!eglChooseConfig (display->egl_disp, attrs, NULL, 0, &count) || count < 1)
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_UNSUPPORTED_FORMAT,
- _("No available configurations for the given pixel format"));
- return FALSE;
- }
-
- configs = g_new (EGLConfig, count);
-
- if (!eglChooseConfig (display->egl_disp, attrs, configs, count, &count) || count < 1)
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_UNSUPPORTED_FORMAT,
- _("No available configurations for the given pixel format"));
- return FALSE;
- }
-
- /* Pick first valid configuration i guess? */
- chosen_config = configs[0];
-
- if (!eglGetConfigAttrib (display->egl_disp, chosen_config,
- EGL_MIN_SWAP_INTERVAL, min_swap_interval_out))
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- "Could not retrieve the minimum swap interval");
- g_free (configs);
- return FALSE;
- }
-
- if (egl_config_out != NULL)
- *egl_config_out = chosen_config;
-
- g_free (configs);
-
- return TRUE;
-}
-
-#define N_EGL_ATTRS 16
-
-static EGLContext
-_create_egl_context (EGLDisplay display,
- EGLConfig config,
- GdkGLContext *share,
- int flags,
- int major,
- int minor,
- gboolean *is_legacy)
-{
- EGLContext ctx;
- EGLint context_attribs[N_EGL_ATTRS];
- int i = 0;
-
- /* ANGLE does not support the GL_OES_vertex_array_object extension, so we need to use ES3 directly */
- context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
- context_attribs[i++] = 3;
-
- /* Specify the flags */
- context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
- context_attribs[i++] = flags;
-
- context_attribs[i++] = EGL_NONE;
- g_assert (i < N_EGL_ATTRS);
-
- ctx = eglCreateContext (display,
- config,
- share != NULL ? GDK_WIN32_GL_CONTEXT (share)->egl_context
- : EGL_NO_CONTEXT,
- context_attribs);
-
- if (ctx != EGL_NO_CONTEXT)
- GDK_NOTE (OPENGL, g_message ("Created EGL context[%p]", ctx));
-
- return ctx;
-}
-#endif /* GDK_WIN32_ENABLE_EGL */
-
-static gboolean
-gdk_win32_gl_context_realize (GdkGLContext *context,
- GError **error)
-{
- GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
-
- gboolean debug_bit, compat_bit, legacy_bit;
- gboolean use_es = FALSE;
-
- /* request flags and specific versions for core (3.2+) WGL context */
- int flags = 0;
- int major = 0;
- int minor = 0;
-
- GdkSurface *surface = gdk_gl_context_get_surface (context);
- GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
- GdkDisplay *display = gdk_surface_get_display (surface);
- GdkWin32Display *win32_display = GDK_WIN32_DISPLAY (display);
- GdkGLContext *share = gdk_display_get_gl_context (display);
-
- gdk_gl_context_get_required_version (context, &major, &minor);
- debug_bit = gdk_gl_context_get_debug_enabled (context);
- compat_bit = gdk_gl_context_get_forward_compatible (context);
-
- /*
- * A legacy context cannot be shared with core profile ones, so this means we
- * must stick to a legacy context if the shared context is a legacy context
- */
- if (share != NULL && gdk_gl_context_is_legacy (share))
- legacy_bit = TRUE;
-
- /* if GDK_GL_LEGACY is set, we default to a legacy context */
- legacy_bit = g_getenv ("GDK_GL_LEGACY") != NULL;
-
- use_es = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) ||
- (share != NULL && gdk_gl_context_get_use_es (share));
-
- if (win32_display->have_wgl || !use_es)
- {
- /* These are the real WGL context items that we will want to use later */
- HGLRC hglrc;
- int pixel_format;
-
- if (!_set_pixformat_for_hdc (context_win32->gl_hdc,
- &pixel_format,
- win32_display))
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_UNSUPPORTED_FORMAT,
- _("No available configurations for the given pixel format"));
-
- return FALSE;
- }
-
- /* if there isn't wglCreateContextAttribsARB() on WGL, use a legacy context */
- if (!legacy_bit)
- legacy_bit = !win32_display->hasWglARBCreateContext;
- if (debug_bit)
- flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
- if (compat_bit)
- flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
-
- GDK_NOTE (OPENGL,
- g_print ("Creating %s WGL context (version:%d.%d, debug:%s, forward:%s, legacy: %s)\n",
- compat_bit ? "core" : "compat",
- major,
- minor,
- debug_bit ? "yes" : "no",
- compat_bit ? "yes" : "no",
- legacy_bit ? "yes" : "no"));
-
- hglrc = _create_gl_context (context_win32->gl_hdc,
- share,
- flags,
- major,
- minor,
- &legacy_bit,
- win32_display->hasWglARBCreateContext);
-
- if (hglrc == NULL)
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- _("Unable to create a GL context"));
- return FALSE;
- }
-
- GDK_NOTE (OPENGL,
- g_print ("Created WGL context[%p], pixel_format=%d\n",
- hglrc,
- pixel_format));
-
- context_win32->hglrc = hglrc;
- }
-
-#ifdef GDK_WIN32_ENABLE_EGL
- else
- {
- EGLContext egl_context;
- EGLContext ctx;
-
- if (debug_bit)
- flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
- if (compat_bit)
- flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
-
- GDK_NOTE (OPENGL, g_message ("Creating EGL context version %d.%d (debug:%s, forward:%s, legacy:%s)",
- major, minor,
- debug_bit ? "yes" : "no",
- compat_bit ? "yes" : "no",
- legacy_bit ? "yes" : "no"));
-
- ctx = _create_egl_context (win32_display->egl_disp,
- context_win32->egl_config,
- share,
- flags,
- major,
- minor,
- &legacy_bit);
-
- if (ctx == EGL_NO_CONTEXT)
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- _("Unable to create a GL context"));
- return FALSE;
- }
-
- GDK_NOTE (OPENGL,
- g_print ("Created EGL context[%p]\n",
- ctx));
-
- context_win32->egl_context = ctx;
- use_es = TRUE;
- }
-#endif
-
- /* set whether we are using GLES */
- gdk_gl_context_set_use_es (context, use_es);
-
- /* Ensure that any other context is created with a legacy bit set */
- gdk_gl_context_set_is_legacy (context, legacy_bit);
-
- return TRUE;
-}
-
-static gboolean
-gdk_win32_gl_context_clear_current (GdkGLContext *context)
-{
- GdkDisplay *display = gdk_gl_context_get_display (context);
- GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
-
-#ifdef GDK_WIN32_ENABLE_EGL
- if (display_win32->egl_disp != EGL_NO_DISPLAY)
- return eglMakeCurrent (display_win32->egl_disp,
- EGL_NO_SURFACE,
- EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
- else
-#endif
- return wglMakeCurrent (NULL, NULL);
-}
-
-static gboolean
-gdk_win32_gl_context_make_current (GdkGLContext *context,
- gboolean surfaceless)
-{
- GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
- GdkDisplay *display = gdk_gl_context_get_display (context);
- GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
- GdkSurface *surface;
-
- gboolean do_frame_sync = FALSE;
-
- if (!gdk_gl_context_get_use_es (context))
- {
- if (!wglMakeCurrent (context_win32->gl_hdc, context_win32->hglrc))
- return FALSE;
-
- if (!surfaceless && display_win32->hasWglEXTSwapControl)
- {
- surface = gdk_gl_context_get_surface (context);
-
- /* If there is compositing there is no particular need to delay
- * the swap when drawing on the offscreen, rendering to the screen
- * happens later anyway, and its up to the compositor to sync that
- * to the vblank. */
- display = gdk_surface_get_display (surface);
- do_frame_sync = ! gdk_display_is_composited (display);
-
- if (do_frame_sync != context_win32->do_frame_sync)
- {
- context_win32->do_frame_sync = do_frame_sync;
-
- if (do_frame_sync)
- wglSwapIntervalEXT (1);
- else
- wglSwapIntervalEXT (0);
- }
- }
- }
-
-#ifdef GDK_WIN32_ENABLE_EGL
- else
- {
- EGLSurface egl_surface;
-
- surface = gdk_gl_context_get_surface (context);
-
- if (!surfaceless)
- egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE);
- else
- {
- if (display_win32->hasEglSurfacelessContext)
- egl_surface = EGL_NO_SURFACE;
- else
- egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, TRUE);
- }
-
- if (!eglMakeCurrent (display_win32->egl_disp,
- egl_surface,
- egl_surface,
- context_win32->egl_context))
- return FALSE;
-
- if (display_win32->egl_min_swap_interval == 0)
- eglSwapInterval (display_win32->egl_disp, 0);
- else
- g_debug ("Can't disable GL swap interval");
- }
-#endif
-
- return TRUE;
-}
+G_DEFINE_ABSTRACT_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT)
static void
gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass)
{
- GdkGLContextClass *gl_context_class = GDK_GL_CONTEXT_CLASS(klass);
- GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gl_context_class->realize = gdk_win32_gl_context_realize;
-
- draw_context_class->begin_frame = gdk_win32_gl_context_begin_frame;
- draw_context_class->end_frame = gdk_win32_gl_context_end_frame;
-
- gobject_class->dispose = _gdk_win32_gl_context_dispose;
}
static void
gdk_win32_gl_context_init (GdkWin32GLContext *self)
{
}
-
-#if 0
-GdkGLContext *
-_gdk_win32_surface_create_gl_context (GdkSurface *surface,
- GError **error)
-{
- GdkDisplay *display = gdk_surface_get_display (surface);
- GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
- GdkWin32GLContext *context = NULL;
- GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
-
-#ifdef GDK_WIN32_ENABLE_EGL
- EGLContext egl_context;
- EGLConfig config;
-#endif
-
- impl->hdc = GetDC (GDK_SURFACE_HWND (surface));
-
-#ifdef GDK_WIN32_ENABLE_EGL
- /* display_win32->hdc_egl_temp should *not* be destroyed here! It is destroyed at dispose()! */
- display_win32->hdc_egl_temp = impl->hdc;
-#endif
-
- if (!_gdk_win32_display_init_gl (display))
- {
- g_set_error_literal (error, GDK_GL_ERROR,
- GDK_GL_ERROR_NOT_AVAILABLE,
- _("No GL implementation is available"));
- return NULL;
- }
-
-#ifdef GDK_WIN32_ENABLE_EGL
- if (display_win32->have_egl && !find_eglconfig_for_window (display_win32, &config,
- &display_win32->egl_min_swap_interval, error))
- return NULL;
-#endif
-
- context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT,
- "surface", surface,
- NULL);
-
- context->gl_hdc = impl->hdc;
-
-#ifdef GDK_WIN32_ENABLE_EGL
- if (display_win32->have_egl)
- context->egl_config = config;
-#endif
-
- return GDK_GL_CONTEXT (context);
-}
-#endif
-
-/**
- * gdk_win32_display_get_wgl_version:
- * @display: a `GdkDisplay`
- * @major: (out): return location for the WGL major version
- * @minor: (out): return location for the WGL minor version
- *
- * Retrieves the version of the WGL implementation.
- *
- * Returns: %TRUE if WGL is available
- */
-gboolean
-gdk_win32_display_get_wgl_version (GdkDisplay *display,
- int *major,
- int *minor)
-{
- g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
-
- if (!GDK_IS_WIN32_DISPLAY (display))
- return FALSE;
-
- if (!_gdk_win32_display_init_gl (display))
- return FALSE;
-
- if (major != NULL)
- *major = GDK_WIN32_DISPLAY (display)->gl_version / 10;
- if (minor != NULL)
- *minor = GDK_WIN32_DISPLAY (display)->gl_version % 10;
-
- return TRUE;
-}
G_BEGIN_DECLS
+#define GDK_WIN32_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WIN32_GL_CONTEXT, GdkWin32GLContextClass))
+#define GDK_WIN32_GL_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WIN32_GL_CONTEXT, GdkWin32GLContextClass))
+#define GDK_WIN32_IS_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WIN32_GL_CONTEXT))
+
struct _GdkWin32GLContext
{
GdkGLContext parent_instance;
-
- /* WGL Context Items */
- HGLRC hglrc;
- HDC gl_hdc;
- guint need_alpha_bits : 1;
-
- /* other items */
- guint do_frame_sync : 1;
-
-#ifdef GDK_WIN32_ENABLE_EGL
- /* EGL (Angle) Context Items */
- EGLContext egl_context;
- EGLConfig egl_config;
-#endif
};
struct _GdkWin32GLContextClass
GdkGLContextClass parent_class;
};
+/* WGL */
+#define GDK_TYPE_WIN32_GL_CONTEXT_WGL (gdk_win32_gl_context_wgl_get_type())
+#define GDK_WIN32_GL_CONTEXT_WGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT_WGL, GdkWin32GLContextWGL))
+#define GDK_IS_WIN32_GL_CONTEXT_WGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT_WGL))
+
+typedef struct _GdkWin32GLContextWGL GdkWin32GLContextWGL;
+
+gboolean gdk_win32_display_init_wgl (GdkDisplay *display,
+ GError **error);
+void gdk_win32_gl_context_wgl_bind_surface (GdkWin32GLContextWGL *ctx,
+ GdkWin32Surface *win32_surface);
+
+GType gdk_win32_gl_context_wgl_get_type (void) G_GNUC_CONST;
+
+/* EGL */
+#define GDK_TYPE_WIN32_GL_CONTEXT_EGL (gdk_win32_gl_context_egl_get_type())
+#define GDK_WIN32_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT_EGL, GdkWin32GLContextEGL))
+#define GDK_IS_WIN32_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT_EGL))
+
+typedef struct _GdkWin32GLContextEGL GdkWin32GLContextEGL;
+
+gboolean gdk_win32_display_init_egl (GdkDisplay *display,
+ GError **error);
+void gdk_win32_surface_destroy_egl_surface (GdkWin32Surface *self);
+
+GType gdk_win32_gl_context_egl_get_type (void) G_GNUC_CONST;
+
void
_gdk_win32_surface_invalidate_egl_framebuffer (GdkSurface *surface);
#ifdef GDK_WIN32_ENABLE_EGL
EGLSurface
-_gdk_win32_surface_get_egl_surface (GdkSurface *surface,
- EGLConfig config,
- gboolean is_dummy)
+gdk_win32_surface_get_egl_surface (GdkSurface *surface,
+ EGLConfig config,
+ gboolean is_dummy)
{
GdkWin32Display *display = GDK_WIN32_DISPLAY (gdk_surface_get_display (surface));
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
gdk_win32_surface_handle_queued_move_resize (GdkDrawContext *draw_context);
#ifdef GDK_WIN32_ENABLE_EGL
-EGLSurface _gdk_win32_surface_get_egl_surface (GdkSurface *surface,
- EGLConfig config,
- gboolean is_dummy);
+EGLSurface gdk_win32_surface_get_egl_surface (GdkSurface *surface,
+ EGLConfig config,
+ gboolean is_dummy);
#endif
G_END_DECLS
'gdkdrop-win32.c',
'gdkevents-win32.c',
'gdkglcontext-win32.c',
+ 'gdkglcontext-win32-wgl.c',
'gdkglobals-win32.c',
'gdkhdataoutputstream-win32.c',
'gdkkeys-win32.c',
if win32_has_egl
GDK_WIN32_EGL_CFLAGS = ['-DGDK_WIN32_ENABLE_EGL']
+ gdk_win32_sources += ['gdkglcontext-win32-egl.c']
endif
gdk_win32_deps = [ # FIXME